﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Linguist.Acoustic;
using Common;

namespace Linguist.Dictionary
{
    /// <summary>
    /// Provides pronunciation information for a word.
    /// </summary>
    public class Pronunciation : IPronunciation
    {
        public static Pronunciation UNKNOWN = new Pronunciation(Unit.EMPTY_ARRAY, null, null, 1.0f);

        private IWord word=null;
        private IWordClassification wordClassification=null;
        private IUnit[] units;
        private String tag=String.Empty;
        private float probability;


        /// <summary>
        /// Creates a pronunciation
        /// </summary>
        /// <param name="units">represents the pronunciation</param>
        /// <param name="tag">a grammar specific tag</param>
        /// <param name="wordClassification">the classification for this word</param>
        /// <param name="probability">the probability of this pronunciation occurring</param> 
        protected Pronunciation(IUnit[] units,
                        String tag,
                        IWordClassification wordClassification,
                        float probability) 
        {
            this.wordClassification = wordClassification;
            this.units = units;
            this.tag = tag;
            this.probability = probability;
        }
        /// <summary>
        /// Creates a pronunciation
        /// </summary>
        /// <param name="units">represents the pronunciation</param>
        /// <param name="tag">a grammar specific tag</param>
        /// <param name="wordClassification">the classification for this word</param>
        /// <param name="probability">the probability of this pronunciation occurring</param> 
        protected Pronunciation(List<IUnit> unitsList,
                      String tag,
                      IWordClassification wordClassification,
                      float probability) 
        {
            this.wordClassification = wordClassification;
            this.units = unitsList.ToArray();
            this.tag = tag;
            this.probability = probability;
        }

        /// <summary>
        /// Creates a pronunciation with defaults
        /// </summary>
        /// <param name="units">represents the pronunciation</param>
        public Pronunciation(List<IUnit> units) 
            :this(units, null, null, 1.0f)
        {
        }
        /// <summary>
        /// Sets the word this pronunciation represents.
        /// </summary>
        /// <param name="word">the Word this Pronunciation represents</param>
        public void setWord(IWord word) 
        {
            if (this.word == null) 
            {
                this.word = word;
            } 
            else 
            {
                throw new Exception("Word of Pronunciation cannot be set twice.");
            }
        }
        /// <summary>
        /// Retrieves the word that this Pronunciation object represents.
        /// </summary>
        /// <returns> the word</returns>
        public IWord getWord() 
        {
            return word;
        }
        /// <summary>
        /// Retrieves the word classification for this pronunciation
        /// </summary>
        /// <returns></returns>
        public IWordClassification getWordClassification() 
        {
            return wordClassification;
        }

        /// <summary>
        /// Retrieves the units for this pronunciation
        /// </summary>
        /// <returns></returns>
        public IUnit[] getUnits() 
        {
            return units;
        }


        public String getTag() 
        {
            /**
            /// Retrieves the tag associated with the pronunciation or null if there is no tag associated with this
            /// pronunciation. Pronunciations can optionally be tagged to allow applications to distinguish between different
            /// pronunciations.
             *
            /// @return the tag or null if no tag is available.
             */

            return tag;
        }

        /// <summary>
        /// Retrieves the probability for the pronunciation. A word may have multiple pronunciations that are not all equally
        /// probable. All probabilities for particular word sum to 1.0.
        /// </summary>
        /// <returns>the probability of this pronunciation as a value between 0 and 1.0.</returns>
        public float getProbability() 
        {
             /*
            ///         TODO: FIX Note that probabilities are currently maintained in the linear domain (unlike just about
            ///         everything else)
             */
            return probability;
        }


        /// <summary>
        /// Dumps a pronunciation
        /// </summary>
        public void dump() 
        {
            Console.Out.WriteLine(ToString());
        }

        /// <summary>
        /// Returns a string representation of this Pronunication. 
        /// </summary>
        /// <returns></returns>
        public String ToString() 
        {
            StringBuilder result = new StringBuilder().Append(word).Append('(');
            foreach (Unit unit in units) 
            {
                result.Append(unit.ToString()).Append(' ');
            }
            result.Append(')');
            return result.ToString();
        }

        /// <summary>
        /// Returns a detailed string representation of this Pronunication.
        /// </summary>
        /// <returns></returns>
        public String toDetailedString() 
        {
            StringBuilder result = new StringBuilder().Append(word).Append(' ');
            foreach (Unit unit in units) 
            {
                result.Append(unit).Append(' ');
            }
            result.Append("\n   class: ").Append(wordClassification)
                .Append(" tag: ").Append(tag).Append(" prob: ").Append(probability);

            return result.ToString();
        }
    }
}
